#include "guish.hpp"
#include <sys/signal.h>

EventManager *eventManager = NULL;

//////////////////////////////////////////////////////////////////////////////

Event::~Event()
{
}

SignalEvent::SignalEvent(int signal)
{
	this->signal = signal;
}

JobFinishedEvent::JobFinishedEvent(int id, PseudoTerminal *pty, int result, ShellState *state)
{
	this->id = id;
	this->pty = pty;
	this->result = result;
	this->state = state;
}

ExitShellEvent::ExitShellEvent(int code)
{
	this->code = code;
}

CrashTestEvent::CrashTestEvent()
{
}

//////////////////////////////////////////////////////////////////////////////

void gotSigChld(int sig)
{
	signal(SIGCHLD, gotSigChld);
	
	Event *event = new SignalEvent(SIGCHLD);
	eventManager->addEvent(event);
}

//////////////////////////////////////////////////////////////////////////////

EventManager::EventManager()
{
	pthread_mutex_init(&lock, NULL);
	pthread_cond_init(&condition, NULL);
	this->notifyPipe = -1;
	this->waking = false;
	
	signal(SIGCHLD, gotSigChld);
}

EventManager::~EventManager()
{
	pthread_mutex_destroy(&lock);
	pthread_cond_destroy(&condition);
}

void EventManager::addEvent(Event *event)
{
	if(!event)
		return;
	
	pthread_mutex_lock(&lock);
		pendingEvents.push_back(event);
	pthread_mutex_unlock(&lock);
		
	notify();
}

void EventManager::notify()
{
	pthread_mutex_lock(&lock);
		if(!waking && notifyPipe >= 0) {
			waking = true;
			char buf[1] = {'x'};
			write(notifyPipe, buf, 1);
		}
		pthread_cond_signal(&condition);
		
	pthread_mutex_unlock(&lock);
}

Event *EventManager::nextEvent()
{
	pthread_mutex_lock(&lock);
		if(!pendingEvents.size()) {
			waking = false;
			pthread_mutex_unlock(&lock);
			return NULL;
		}
		
		Event *ret = pendingEvents[0];
		pendingEvents.pop_front();
	pthread_mutex_unlock(&lock);
	
	return ret;
}

void EventManager::waitForEvents()
{
	pthread_mutex_lock(&lock);
	while(!pendingEvents.size())
		pthread_cond_wait(&condition, &lock);
	pthread_mutex_unlock(&lock);
}

void EventManager::setNotifyPipe(int fd)
{
	this->notifyPipe = fd;
}

